package com.swt.gap.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.swt.gap.common.FileTypeEnum;
import com.swt.gap.common.constant.CommonConstant;
import com.swt.gap.common.constant.GraphDbConstant;
import com.swt.gap.config.ExtractConfig;
import com.swt.gap.dao.*;
import com.swt.gap.model.dto.*;
import com.swt.gap.model.entity.File;
import com.swt.gap.model.entity.OntologyNode;
import com.swt.gap.model.entity.TaskSubscribeData;
import com.swt.gap.model.entity.TaskSubscribeRule;
import com.swt.gap.model.vo.EventExtractVO;
import com.swt.gap.model.vo.FileMetaInfo;
import com.swt.gap.model.vo.TaskVO;
import com.swt.gap.model.vo.element.EventElementVO;
import com.swt.gap.util.FileCharsetUtil;
import com.swt.gap.util.UserLoginUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.xmlbeans.XmlException;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class FileTask {

    private final RestTemplate restTemplate;
    private final ExtractConfig extractConfig;
    private final OntologyNodeService ontologyNodeService;
    private final OntologyNodeDao ontologyNodeDao;
    private final FileDao fileDao;
    private final TaskSubscribeRuleDao taskSubscribeRuleDao;
    private final FileClassDao fileClassDao;
    private final TaskSubscribeDataDao taskSubscribeDataDao;
    private final SysGroupService sysGroupService;
    private final TaskDao taskDao;

    public FileTask(RestTemplate restTemplate,
                    ExtractConfig extractConfig,
                    OntologyNodeService ontologyNodeService,
                    OntologyNodeDao ontologyNodeDao,
                    FileDao fileDao,
                    TaskSubscribeRuleDao taskSubscribeRuleDao,
                    FileClassDao fileClassDao,
                    TaskSubscribeDataDao taskSubscribeDataDao,
                    SysGroupService sysGroupService,
                    TaskDao taskDao) {
        this.restTemplate = restTemplate;
        this.extractConfig = extractConfig;
        this.ontologyNodeService = ontologyNodeService;
        this.ontologyNodeDao = ontologyNodeDao;
        this.fileDao = fileDao;
        this.taskSubscribeRuleDao = taskSubscribeRuleDao;
        this.fileClassDao = fileClassDao;
        this.taskSubscribeDataDao = taskSubscribeDataDao;
        this.sysGroupService = sysGroupService;
        this.taskDao = taskDao;
    }
    /*@Async
    public void saveFile(FileMetaInfo fileInfo) {
        log.info("fileName:" + fileInfo.getOriginalFileName());
        File file = new File();
        BeanUtils.copyProperties(fileInfo, file);

        String path = CommonConstant.UPLOAD_DIR + fileInfo.getSavedFileName();
        String content = "";
        if (path.endsWith(FileTypeEnum.TXT.getSuffix())) {
            content = getTextData(path);
        } else {
            content = getWordData(path);
        }
        EventExtractVO eventExtractVO = null;
        if (StringUtils.hasLength(content)) {
            eventExtractVO = parseElement(content);
            file.setTextElement((JSONObject) JSON.toJSON(eventExtractVO));
        }
        addFile(file);
        *//*if (isOpenEs) {
            addFileToEs(file.getFileId(), content, eventExtractVO);
        }*//*
        Optional.ofNullable(eventExtractVO).ifPresent(e -> checkSubscribe(file, e));
    }*/


    private String getTextData(String filePath) {
        StringBuilder fileContent = new StringBuilder();
        String fileCharset = FileCharsetUtil.getFilecharset(new java.io.File(filePath));
        BufferedReader br = null;
        try {
            InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), fileCharset);
            br = new BufferedReader(isr);
            String line;
            while ((line = br.readLine()) != null) {
                line += '\n';
                fileContent.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return fileContent.toString();

    }


    private String getWordData(String filePath) {
        String wordData = "";
        try {
            if (filePath.endsWith(FileTypeEnum.WORD03.getSuffix())) {
                FileInputStream fis = new FileInputStream(filePath);
                WordExtractor wordExtractor = new WordExtractor(fis);
                wordData = wordExtractor.getText();

            } else if (filePath.endsWith(FileTypeEnum.WORD07.getSuffix())) {
                OPCPackage opcPackage = POIXMLDocument.openPackage(filePath);
                POIXMLTextExtractor extractor = new XWPFWordExtractor(opcPackage);
                wordData = extractor.getText();
            }
        } catch (IOException | XmlException | OpenXML4JException e) {
            e.printStackTrace();
        }

        return wordData;

    }

    public EventExtractVO parseElement(String text) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HashMap<String, Object> requestBody = new HashMap<>();
        // id为任意字符串，用来区分不同的请求
        requestBody.put("id", new Random(1).nextInt(100));
        requestBody.put("text", text);
        HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(requestBody, headers);
        // 事件类型
        EventClassDTO eventClassDTO = restTemplate.postForEntity(extractConfig.getEventClass(), httpEntity, EventClassDTO.class).getBody();

        // 事件要素
        EventElementParsDTO eventElementParsDTO = restTemplate.postForEntity(extractConfig.getElement(), httpEntity, EventElementParsDTO.class).getBody();

        String labels = Objects.requireNonNull(eventClassDTO).getResults();
        if (labels.contains("-")) {
            labels = labels.substring(labels.indexOf("-") + 1);
        }
        List<OntologyNode> ontologyNodes = ontologyNodeDao.selectByLabels("事件," + labels);
        if (!CollectionUtils.isEmpty(ontologyNodes)) {
            int nodeId = ontologyNodeDao.selectByLabels("事件," + labels).get(0).getNodeId();
            List<EventElementVO> eventRelElementsOntology = ontologyNodeService.listEventElementsAndRelNodeById(nodeId);
            assert eventElementParsDTO != null;
            List<ElementValueDTO> eventElements = new ArrayList<>();
            for (EventElementVO eventElement : eventRelElementsOntology) {
                ElementValueDTO elementValue = new ElementValueDTO();
                BeanUtils.copyProperties(eventElement, elementValue);
                List<TextIndex> elements = new ArrayList<>();
                for (EventElementParsDTO.ResultsDTO.ParsDTO par : eventElementParsDTO.getResults().getPars()) {
                    int parStartIndex = par.getParBegin();
                    for (EventElementParsDTO.ResultsDTO.ParsDTO.SentsDTO sent : par.getSents()) {
                        int sentStartIndex = sent.getSentBegin();
                        for (EventElementParsDTO.ResultsDTO.ParsDTO.SentsDTO.PredEntityMentionsDTO entity : sent.getPredEntityMentions()) {
                            if (entity.getSubtypeCn().equals(eventElement.getElement())) {
                                TextIndex textIndex = TextIndex.builder()
                                        .text(entity.getText())
                                        .startIndex(parStartIndex + sentStartIndex + entity.getBegin())
                                        .endIndex(parStartIndex + sentStartIndex + entity.getEnd())
                                        .build();
                                elements.add(textIndex);
                            }

                        }
                        for (EventElementParsDTO.ResultsDTO.ParsDTO.SentsDTO.PredTimeSpaceMentionsDTO timeSpace : sent.getPredTimeSpaceMentions()) {
                            if (timeSpace.getTypeCn().equals(eventElement.getElement())) {
                                TextIndex textIndex = TextIndex.builder()
                                        .text(timeSpace.getText())
                                        .startIndex(parStartIndex + sentStartIndex + timeSpace.getBegin())
                                        .endIndex(parStartIndex + sentStartIndex + timeSpace.getEnd())
                                        .build();
                                elements.add(textIndex);
                            }
                            if ("时间".equals(timeSpace.getTypeCn()) && "开始时间".equals(eventElement.getElement())) {
                                TextIndex textIndex = TextIndex.builder()
                                        .text(timeSpace.getNormalization())
                                        .startIndex(parStartIndex + sentStartIndex + timeSpace.getBegin())
                                        .endIndex(parStartIndex + sentStartIndex + timeSpace.getEnd())
                                        .build();
                                elements.add(textIndex);
                            }
                        }
                    }
                }
                if (elementValue.getElement().equals(GraphDbConstant.PROPERTY_KEY_DESCRIPTION)) {
                    elements.add(new TextIndex(0,0, text));
                }
                elementValue.setElementTexts(elements);
                eventElements.add(elementValue);
            }

            return EventExtractVO.builder()
                    .eventOntologyNodeName(labels)
                    .eventOntologyNodeId(nodeId)
                    .eventElements(eventElements)
                    .build();
        } else {
            return new EventExtractVO();
        }
    }

    public Integer addFile(File file) {
        int userId = UserLoginUtils.getUser().getUserId();

        file.setCreatedBy(userId);
        file.setCreatedTime(new Date());
        file.setIsDeleted(false);
        //数据来源
        file.setFileFromType(2);
        fileDao.insertSelective(file);

        return file.getFileId();
    }

    @Async
    public void checkSubscribe(File file, EventExtractVO eventExtract, Integer loginUserId) {
        List<Integer> userIds = sysGroupService.listSameGroupUserByUserId(loginUserId);
        Page<TaskVO> tasks = taskDao.getTaskByStatusAndGroup2(null, userIds, 1);
        Set<Integer> taskIds = tasks.getResult().stream().map(TaskVO :: getTaskId).collect(Collectors.toSet());

        List<TaskSubscribeRule> taskSubscribeRules = taskSubscribeRuleDao.selectByTaskIds(taskIds);
        taskSubscribeRules.forEach(taskSubscribeRule -> {
            boolean isMatch = false;
            List<SubscribeRuleDTO> subscribeRules = JSONObject.parseArray(taskSubscribeRule.getRule().toJSONString(), SubscribeRuleDTO.class);
            for(SubscribeRuleDTO rule : subscribeRules) {
                boolean isMatchEvent = rule.getOntologyNodeName().equals(eventExtract.getEventOntologyNodeName());
                boolean hasElementRule = null != rule.getElements() && !rule.getElements().isEmpty();
                if (isMatchEvent && !hasElementRule) {
                    isMatch = true;
                    break;
                } else if (isMatchEvent) {
                    List<ElementSubscribeDTO> elementSubscribeRules = rule.getElements();
                    isMatch = elementSubscribeRules.stream()
                            .anyMatch(elementSubscribeRule -> eventExtract.getEventElements().stream()
                                    .anyMatch(elementValue -> {
                                        boolean isMatchElementType = elementValue.getElement().equals(elementSubscribeRule.getElement());
                                        boolean isMatchElementValue = elementValue.getElementTexts().stream()
                                                .anyMatch(textIndex -> textIndex.getText().equals(elementSubscribeRule.getSubscribeValue()));
                                        return isMatchElementType && isMatchElementValue;
                                    })
                            );
                    if (isMatch) {
                        break;
                    }

                }
            }
            if (isMatch) {
                String fileClassName = fileClassDao.selectByPrimaryKey(file.getFileClassId()).getClassName();
                SubscribeFileDTO subscribeFile = SubscribeFileDTO.builder()
                        .fileClassName(fileClassName)
                        .build();
                file.setTextElement(null);
                BeanUtils.copyProperties(file, subscribeFile);

                TaskSubscribeData taskSubscribeData = TaskSubscribeData.builder()
                        .taskId(taskSubscribeRule.getTaskId())
                        .fileId(file.getFileId())
                        .fileContent(JSON.toJSONString(subscribeFile))
                        .status(1)
                        .createdTime(new Date())
                        .build();
                taskSubscribeDataDao.insertSelective(taskSubscribeData);
            }
        });
    }
}
